﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using IOA.MES.Log.Business;
using IOA.MES.Log.DataAccess.VModel;
using IOA.Utils;
using NLog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;

namespace IOA.MES.Business
{
    /// <summary>
    /// 返工管理（错误代码：140001）
    /// </summary>
    public class ReworkMgr
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private MESContext mesDb = new MESContext("MES");

        /// <summary>
        /// 创建返修工单
        /// </summary>
        /// <param name="model">工单对象</param>
        public void SaveRework(VReworkOrder model)
        {
            var workshop = new WorkshopMgr().GetWorkshop(model.WorkshopCode);
            if (workshop == null)
            {
                throw new MultiLanBizException(134002);  // 车间不存在或已被删除，无法编辑
            }
            if (string.IsNullOrWhiteSpace(model.ReworkNo))
            {
                model.PkId = 0;
                var rework = Mapper.Map<ReworkOrder>(model);
                rework.CreateTime = DateTime.Now;
                rework.WorkshopName = workshop.WorkshopName;
                mesDb.ReworkOrders.Add(rework);
                mesDb.SaveChanges();
                rework.ReworkNo = $"{DateTime.Now:yyMMddHHmmss}{(rework.PkId % 100).ToString("00")}";

                model.Sites.ForEach(_ =>
                {
                    _.SiteName = !Enum.IsDefined(typeof(SiteType), _.SiteType) ? string.Empty : EnumConvert.ToDesc(_.SiteType);
                    _.ReworkNo = rework.ReworkNo;
                    _.CreateBy = rework.CreateBy;
                    _.CreateTime = DateTime.Now;
                });

                var sites = Mapper.Map<List<ReworkSite>>(model.Sites);
                mesDb.ReworkSites.AddRange(sites);
                mesDb.SaveChanges();
            }
            else
            {
                var entity = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == model.ReworkNo && _.Valid);
                if (entity == null)
                {
                    throw new MultiLanBizException(140001);//返修单不存在
                }
                mesDb.ReworkOrders.Attach(entity);
                entity.WorkshopCode = model.WorkshopCode;
                entity.WorkshopName = workshop.WorkshopName;
                entity.ReworkType = model.ReworkType;
                entity.Remark = model.Remark;
                entity.ModifyBy = model.ModifyBy;
                entity.ModifyTime = DateTime.Now;

                var dbSites = mesDb.ReworkSites.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
                var newSites = Mapper.Map<List<ReworkSite>>(model.Sites.Where(site => !dbSites.Select(_ => _.SiteType).Contains(site.SiteType)).ToList());
                var removeSites = dbSites.Where(site => !model.Sites.Select(_ => _.SiteType).Contains(site.SiteType)).ToList();
                var updateSites = dbSites.Where(site => model.Sites.Select(_ => _.SiteType).Contains(site.SiteType)).ToList();

                removeSites.ForEach(_ =>
                {
                    mesDb.ReworkSites.Attach(_);
                    _.Valid = false;
                    _.ModifyBy = model.ModifyBy;
                    _.ModifyTime = DateTime.Now;
                });
                updateSites.ForEach(_ =>
                {
                    var newSite = model.Sites.FirstOrDefault(s => s.SiteType == _.SiteType);
                    mesDb.ReworkSites.Attach(_);
                    _.SiteName = !Enum.IsDefined(typeof(SiteType), _.SiteType) ? string.Empty : EnumConvert.ToDesc(_.SiteType);
                    _.UseMaterials = newSite.UseMaterials;
                    _.ModifyBy = model.ModifyBy;
                    _.ModifyTime = DateTime.Now;
                });
                newSites.ForEach(_ =>
                {
                    _.SiteName = !Enum.IsDefined(typeof(SiteType), _.SiteType) ? string.Empty : EnumConvert.ToDesc(_.SiteType);
                    _.ReworkNo = entity.ReworkNo;
                    _.CreateBy = entity.ModifyBy;
                    _.CreateTime = DateTime.Now;
                });
                mesDb.ReworkSites.AddRange(newSites);
                mesDb.SaveChanges();
            }
        }

        /// <summary>
        /// 批量添加返修对象
        /// </summary>
        /// <param name="reworkNo">返修单号</param>
        /// <param name="items">返修对象列表</param>
        public void AddReworkItems(VReworkOrder model, List<VReworkItem> items)
        {
            if (!items.Any())
            {
                throw new MultiLanBizException(140004);//请至少添加一个对象
            }
            var rework = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == model.ReworkNo && _.Valid);
            if (rework == null)
            {
                throw new MultiLanBizException(140001);//返修单不存在
            }
            else if (rework.ReviewStatus == ReviewStatus.Reviewed)
            {
                throw new MultiLanBizException(140005);//审核通过的返工单无法追加返工对象，您可新建返工单
            }

            mesDb.ReworkOrders.Attach(rework);
            var itemNos = items.Select(_ => _.ReworkItemNo).ToList();
            if (rework.ReworkType == ReworkType.ByPack)
            {
                var dbItems = mesDb.Packs.AsNoTracking().Where(_ => itemNos.Contains(_.PackNo) && _.Valid).ToList();
                if (itemNos.Any(itemNo => !dbItems.Select(_ => _.PackNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase)))
                {
                    throw new MultiLanBizException(140006, string.Join(", ", itemNos.Where(itemNo => !dbItems.Select(_ => _.PackNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase))));//如下返工对象不存在
                }
                else if (!string.IsNullOrWhiteSpace(rework.OrderNo))
                {
                    var otherOrderItems = dbItems.Where(_ => !StringUtils.Equals(rework.OrderNo, _.OrderNo)).Select(_ => _.PackNo).ToList();
                    if (otherOrderItems.Any())
                    {
                        throw new MultiLanBizException(140009, string.Join(", ", otherOrderItems));//一个返工单仅允许有一个订单，下列返工对象不在当前订单中
                    }
                }
                else
                {
                    rework.OrderNo = dbItems.FirstOrDefault().OrderNo;
                }
            }
            else if (rework.ReworkType == ReworkType.ByCabinet)
            {
                var dbItems = mesDb.Cabinets.AsNoTracking().Where(_ => itemNos.Contains(_.CabinetNo) && _.Valid).ToList();
                if (itemNos.Any(itemNo => !dbItems.Select(_ => _.CabinetNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase)))
                {
                    throw new MultiLanBizException(140006, string.Join(", ", itemNos.Where(itemNo => !dbItems.Select(_ => _.CabinetNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase))));//如下返工对象不存在
                }
                else if (!string.IsNullOrWhiteSpace(rework.OrderNo))
                {
                    var packs = mesDb.Packs.AsNoTracking().Where(_ => itemNos.Contains(_.CabinetNo) && _.Valid).ToList();
                    if (!packs.Any())
                    {
                        throw new MultiLanBizException(140012);//柜中没有组件
                    }
                    var otherOrderItems = packs.Where(_ => !StringUtils.Equals(rework.OrderNo, _.OrderNo)).ToList();
                    if (otherOrderItems.Any())
                    {
                        throw new MultiLanBizException(140010, string.Join(", ", otherOrderItems.Select(_ => $"{_.CabinetNo}:{_.PackNo}")));//一个返工单仅允许有一个订单，下列柜中存在其他订单包装
                    }
                }
                else
                {
                    var packs = mesDb.Packs.AsNoTracking().Where(_ => itemNos.Contains(_.CabinetNo) && _.Valid).ToList();
                    if (packs.Select(_ => _.OrderNo).Distinct().Count() > 1)
                    {
                        throw new MultiLanBizException(140011, string.Join(", ", packs.Select(_ => _.OrderNo).Distinct()));//一个返工单仅允许有一个订单，本次添加的对象存在多个订单
                    }
                    if (!packs.Any())
                    {
                        throw new MultiLanBizException(140012);//柜中没有组件
                    }
                    rework.OrderNo = packs.FirstOrDefault().OrderNo;
                }
            }
            else if (rework.ReworkType == ReworkType.ByWorkOrder)
            {
                var dbItems = mesDb.WorkOrders.AsNoTracking().Where(_ => itemNos.Contains(_.WorkOrderNo) && _.Valid).ToList();
                if (itemNos.Any(itemNo => !dbItems.Select(_ => _.WorkOrderNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase)))
                {
                    throw new MultiLanBizException(140006, string.Join(", ", itemNos.Where(itemNo => !dbItems.Select(_ => _.WorkOrderNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase))));//如下返工对象不存在
                }
                else if (!string.IsNullOrWhiteSpace(rework.OrderNo))
                {
                    var otherOrderItems = dbItems.Where(_ => !StringUtils.Equals(rework.OrderNo, _.OrderNo)).Select(_ => _.WorkOrderNo).ToList();
                    if (otherOrderItems.Any())
                    {
                        throw new MultiLanBizException(140009, string.Join(", ", otherOrderItems));//一个返工单仅允许有一个订单，下列返工对象不在当前订单中
                    }
                }
                else
                {
                    rework.OrderNo = dbItems.FirstOrDefault().OrderNo;
                }
            }
            else if (rework.ReworkType == ReworkType.ByOrder)
            {
                var workOrders = mesDb.WorkOrders.AsNoTracking().Where(_ => itemNos.Contains(_.OrderNo) && _.Valid).ToList();
                if (itemNos.Any(itemNo => !workOrders.Select(_ => _.OrderNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase)))
                {
                    throw new MultiLanBizException(140006, string.Join(", ", itemNos.Where(itemNo => !workOrders.Select(_ => _.OrderNo).Contains(itemNo, StringComparer.CurrentCultureIgnoreCase))));//如下返工对象不存在
                }
                else if (!string.IsNullOrWhiteSpace(rework.OrderNo))
                {
                    var otherOrderItems = workOrders.Where(_ => !StringUtils.Equals(rework.OrderNo, _.OrderNo)).Select(_ => _.OrderNo).ToList();
                    if (otherOrderItems.Any())
                    {
                        throw new MultiLanBizException(140009, string.Join(", ", otherOrderItems));//一个返工单仅允许有一个订单，下列返工对象不在当前订单中
                    }
                }
                else
                {
                    rework.OrderNo = workOrders.FirstOrDefault().OrderNo;
                }
            }
            else
            {
                throw new Exception("返工单类型枚举错误");
            }

            if (string.IsNullOrWhiteSpace(rework.CustomerCode))
            {
                var fstComponent = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.OrderNo == rework.OrderNo && _.Valid);
                if (fstComponent == null)
                {
                    throw new MultiLanBizException(117002);  // 订单不存在或已被删除，无法修改
                }
                rework.CustomerCode = fstComponent.CustomerCode;
                rework.CustomerName = fstComponent.CustomerName;
            }

            var reworkItems = mesDb.ReworkItems.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
            var newItems = items.Where(item => !reworkItems.Select(_ => _.ReworkItemNo).Contains(item.ReworkItemNo, StringComparer.CurrentCultureIgnoreCase) && item.Valid).ToList();
            mesDb.ReworkItems.AddRange(newItems.Select(_ => new ReworkItem
            {
                ReworkNo = model.ReworkNo,
                CreateBy = model.ModifyBy,
                CreateTime = DateTime.Now,
                ProduceStatus = ProduceStatus.NotProduced,
                ReworkItemNo = _.ReworkItemNo
            }));

            mesDb.SaveChanges();
        }

        /// <summary>
        /// 移除返工对象
        /// </summary>
        /// <param name="model">返工对象</param>
        public void RemoveReworkItem(VReworkItem model)
        {
            var rework = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == model.ReworkNo && _.Valid);
            if (rework == null)
            {
                throw new MultiLanBizException(140001);//返修单不存在
            }
            else if (rework.ReviewStatus == ReviewStatus.Reviewed)
            {
                throw new MultiLanBizException(140005);//审核通过的返工单无法追加返工对象，您可新建返工单
            }

            var reworkItems = mesDb.ReworkItems.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.ReworkItemNo == model.ReworkItemNo && _.Valid).ToList();
            reworkItems.ForEach(_ =>
            {
                mesDb.ReworkItems.Attach(_);
                _.Valid = false;
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
            });
            mesDb.SaveChanges();
        }

        /// <summary>
        /// 提交审核
        /// </summary>
        /// <param name="model">返工单对象</param>
        public void SubmitReview(VReworkOrder model)
        {
            var rework = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == model.ReworkNo && _.Valid);
            if (rework == null)
            {
                throw new MultiLanBizException(140001);//返工单不存在
            }
            else if (rework.ReviewStatus == ReviewStatus.Reviewed)
            {
                throw new MultiLanBizException(140007);//返工单已审核通过，无需重复提交
            }
            else if (rework.ReviewStatus == ReviewStatus.UnReviewed)
            {
                throw new MultiLanBizException(140008);//返工单已提交，请耐心等待审核
            }

            mesDb.ReworkOrders.Attach(rework);
            rework.ReviewStatus = ReviewStatus.UnReviewed;
            rework.ReviewBy = 0;
            rework.ReviewTime = null;
            rework.ModifyBy = model.ModifyBy;
            rework.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 处理返工组件清单
                    var components = new List<Component>();
                    var items = mesDb.ReworkItems.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
                    var itemNos = items.Select(_ => _.ReworkItemNo).Distinct().ToList();
                    switch (rework.ReworkType)
                    {
                        case ReworkType.ByPack:
                            components.AddRange(mesDb.Components.AsNoTracking().Where(_ => itemNos.Contains(_.PackNo) && _.Valid).ToList());
                            break;
                        case ReworkType.ByCabinet:
                            components.AddRange(mesDb.Components.AsNoTracking().Where(_ => itemNos.Contains(_.CabinetNo) && _.Valid).ToList());
                            break;
                        case ReworkType.ByWorkOrder:
                            components.AddRange(mesDb.Components.AsNoTracking().Where(_ => itemNos.Contains(_.WorkOrderNo) && _.Valid).ToList());
                            break;
                        case ReworkType.ByOrder:
                            components.AddRange(mesDb.Components.AsNoTracking().Where(_ => itemNos.Contains(_.OrderNo) && _.Valid).ToList());
                            break;
                    }
                    var existComponents = mesDb.ReworkProducts.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
                    var newComponents = components.Where(p => !existComponents.Select(_ => _.BarCode).Contains(p.BarCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    var removeComponents = existComponents.Where(p => !components.Select(_ => _.BarCode).Contains(p.BarCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    var updateComponents = existComponents.Where(p => components.Select(_ => _.BarCode).Contains(p.BarCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    removeComponents.ForEach(_ =>
                    {
                        mesDb.ReworkProducts.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    updateComponents.ForEach(_ =>
                    {
                        mesDb.ReworkProducts.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.ReworkProducts.AddRange(newComponents.Select(_ => new ReworkProduct
                    {
                        BarCode = _.BarCode,
                        CabinetNo = _.CabinetNo,
                        OrderNo = _.OrderNo,
                        PackBatchNo = _.PackBatchNo,
                        PackNo = _.PackNo,
                        ProduceStatus = ProduceStatus.NotProduced,
                        ProductCode = _.ProductCode,
                        ProductName = _.ProductName,
                        ReworkNo = model.ReworkNo,
                        WorkOrderNo = _.WorkOrderNo,
                        WorkshopCode = _.WorkshopCode,
                        WorkshopName = _.WorkshopName,
                        CreateBy = model.ModifyBy,
                        CreateTime = DateTime.Now
                    }));
                    mesDb.SaveChanges();
                    #endregion

                    #region 处理返工扣料
                    var reworkBoms = new List<ReworkBom>();
                    var sites = mesDb.ReworkSites.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.UseMaterials && _.Valid).ToList();
                    if (sites.Any())
                    {
                        var workOrderNos = components.Select(_ => _.WorkOrderNo).Distinct().ToList();
                        var siteTypes = sites.Select(_ => _.SiteType).Distinct().ToList();
                        var wokrOrderBoms = mesDb.ProductSiteBoms.AsNoTracking().Where(_ => workOrderNos.Contains(_.WorkOrderNo) && siteTypes.Contains(_.SiteType) && _.Valid).ToList();
                        var categories = !components.Any() ? new List<ProductCategory>() : mesDb.ProductCategories.AsNoTracking().Where(_ => _.Valid).ToList();

                        foreach (var workorder in components.GroupBy(_ => _.WorkOrderNo))
                        {
                            var curBoms = wokrOrderBoms.Where(_ => StringUtils.Equals(workorder.Key, _.WorkOrderNo)).ToList();
                            foreach (var bom in curBoms)
                            {
                                //var category = GetBomCategory(bom.BomCategoryCode, categories);
                                //if (category == null)
                                //{
                                //    continue;
                                //}
                                //var curReworkBom = reworkBoms.FirstOrDefault(_ => StringUtils.Equals(_.CategoryCode, category.CategoryCode));
                                //if (curReworkBom != null)
                                //{
                                //    curReworkBom.Quality = curReworkBom.Quality + bom.BomCount;
                                //}
                                //else
                                //{
                                //    reworkBoms.Add(new ReworkBom
                                //    {
                                //        CategoryCode = category.CategoryCode,
                                //        CategoryName = category.CategoryName,
                                //        Quality = bom.BomCount,
                                //        ReworkNo = rework.ReworkNo,
                                //        CreateBy = model.CreateBy,
                                //        CreateTime = DateTime.Now
                                //    });
                                //}
                            }
                        }
                    }
                    var existReworkBoms = mesDb.ReworkBoms.Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
                    var newReworkBoms = reworkBoms.Where(bom => !existReworkBoms.Select(_ => _.CategoryCode).Contains(bom.CategoryCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    var removeReworkBoms = existReworkBoms.Where(bom => !reworkBoms.Select(_ => _.CategoryCode).Contains(bom.CategoryCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    var updateReworkBoms = existReworkBoms.Where(bom => reworkBoms.Select(_ => _.CategoryCode).Contains(bom.CategoryCode, StringComparer.CurrentCultureIgnoreCase)).ToList();
                    removeReworkBoms.ForEach(_ =>
                    {
                        mesDb.ReworkBoms.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    updateReworkBoms.ForEach(_ =>
                    {
                        var curBom = reworkBoms.FirstOrDefault(bom => StringUtils.Equals(bom.CategoryCode, _.CategoryCode));
                        mesDb.ReworkBoms.Attach(_);
                        _.Quality = curBom.Quality;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.ReworkBoms.AddRange(newReworkBoms);
                    mesDb.SaveChanges();
                    #endregion

                    model = Mapper.Map<VReworkOrder>(rework);
                    var user = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault();
                    var logs = newComponents.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "提交返工",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"组件被提交返工审核，本次{model.CNReworkType}，共需返工{itemNos.Count}" + (model.ReworkType == ReworkType.ByOrder ? "个订单" : (model.ReworkType == ReworkType.ByWorkOrder ? "个工单" : (model.ReworkType == ReworkType.ByCabinet ? "柜" : "包"))) + $"，合{components.Count}块",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"处理返工单足见清单和扣料清单是出现未知错误：{ex.Message}");
                }
            });
        }

        private ProductCategory GetBomCategory(string categoryCode, List<ProductCategory> categories)
        {
            var category = categories.FirstOrDefault(_ => StringUtils.Equals(categoryCode, _.CategoryCode));
            if (category == null)
            {
                return null;
            }
            else if (category.Level <= 2)
            {
                return category;
            }
            else
            {
                return GetBomCategory(categories.FirstOrDefault(_ => _.PkId == category.ParentId)?.CategoryCode, categories);
            }
        }

        /// <summary>
        /// 获取返工工单
        /// </summary>
        /// <param name="reworkNo">返工单号</param>
        /// <returns>返工工单</returns>
        public List<VReworkOrder> QueryReworks(int page, int limit, out int total, string orderNo, string reworkNo, string workshopCode, ReviewStatus? reviewStatus, ProduceStatus? produceStatus, ReworkType? reworkType, DateTime? startDate, DateTime? endDate)
        {
            var query = mesDb.ReworkOrders.AsNoTracking().Where(_ => _.Valid);
            if (!string.IsNullOrWhiteSpace(orderNo))
            {
                query = query.Where(_ => _.OrderNo.Contains(orderNo));
            }
            if (!string.IsNullOrWhiteSpace(reworkNo))
            {
                query = query.Where(_ => _.ReworkNo.Contains(reworkNo));
            }
            if (!string.IsNullOrWhiteSpace(workshopCode))
            {
                query = query.Where(_ => _.WorkshopCode == workshopCode);
            }
            if (reviewStatus.HasValue)
            {
                query = query.Where(_ => _.ReviewStatus == reviewStatus.Value);
            }
            if (produceStatus.HasValue)
            {
                query = query.Where(_ => _.ProduceStatus == produceStatus.Value);
            }
            if (reworkType.HasValue)
            {
                query = query.Where(_ => _.ReworkType == reworkType.Value);
            }
            if (startDate.HasValue)
            {
                query = query.Where(_ => _.CreateTime >= startDate.Value);
            }
            if (endDate.HasValue)
            {
                query = query.Where(_ => _.CreateTime < endDate.Value);
            }

            total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);

            var entities = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();
            var models = Mapper.Map<List<VReworkOrder>>(entities);

            var reworkNos = models.Select(_ => _.ReworkNo).Distinct().ToList();
            var sites = mesDb.ReworkSites.AsNoTracking().Where(_ => reworkNos.Contains(_.ReworkNo) && _.Valid).ToList();

            var userIds = models.Select(_ => _.CreateBy).Distinct().ToList();
            userIds.AddRange(models.Where(_ => _.ReviewBy > 0).Select(_ => _.ReviewBy));
            var users = new UserMgr().QueryUsers(userIds.Distinct().ToList());

            models.ForEach(model =>
            {
                model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
                model.Sites = Mapper.Map<List<VReworkSite>>(sites.Where(_ => StringUtils.Equals(_.ReworkNo, model.ReworkNo)).ToList());
                model.CNReviewBy = users.FirstOrDefault(_ => _.PkId == model.ReviewBy)?.TrueName;
            });

            return models;
        }

        /// <summary>
        /// 获取计划的返工工单
        /// </summary>
        /// <param name="reworkNo">返工单号</param>
        /// <returns>返工工单</returns>
        public List<VReworkOrder> QueryPlanReworks(int page, int limit, out int total, string orderNo, string reworkNo, string workshopCode, ReviewStatus? reviewStatus, ProduceStatus? produceStatus, ReworkType? reworkType, DateTime? startDate, DateTime? endDate)
        {
            var query = mesDb.ReworkOrders.AsNoTracking().Where(_ => _.Valid);
            if (!string.IsNullOrWhiteSpace(orderNo))
            {
                query = query.Where(_ => _.OrderNo.Contains(orderNo));
            }
            if (!string.IsNullOrWhiteSpace(reworkNo))
            {
                query = query.Where(_ => _.ReworkNo.Contains(reworkNo));
            }
            if (!string.IsNullOrWhiteSpace(workshopCode))
            {
                query = query.Where(_ => _.WorkshopCode == workshopCode);
            }
            if (reviewStatus.HasValue)
            {
                query = query.Where(_ => _.ReviewStatus == reviewStatus.Value);
            }
            else
            {
                query = query.Where(_ => _.ReviewStatus != ReviewStatus.UnSubmit);
            }
            if (produceStatus.HasValue)
            {
                query = query.Where(_ => _.ProduceStatus == produceStatus.Value);
            }
            if (reworkType.HasValue)
            {
                query = query.Where(_ => _.ReworkType == reworkType.Value);
            }
            if (startDate.HasValue)
            {
                query = query.Where(_ => _.CreateTime >= startDate.Value);
            }
            if (endDate.HasValue)
            {
                query = query.Where(_ => _.CreateTime < endDate.Value);
            }

            total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);

            var entities = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();
            var models = Mapper.Map<List<VReworkOrder>>(entities);

            var reworkNos = models.Select(_ => _.ReworkNo).Distinct().ToList();
            var sites = mesDb.ReworkSites.AsNoTracking().Where(_ => reworkNos.Contains(_.ReworkNo) && _.Valid).ToList();

            var userIds = models.Select(_ => _.CreateBy).Distinct().ToList();
            userIds.AddRange(models.Where(_ => _.ReviewBy > 0).Select(_ => _.ReviewBy));
            var users = new UserMgr().QueryUsers(userIds.Distinct().ToList());

            models.ForEach(model =>
            {
                model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
                model.Sites = Mapper.Map<List<VReworkSite>>(sites.Where(_ => StringUtils.Equals(_.ReworkNo, model.ReworkNo)).ToList());
                model.CNReviewBy = users.FirstOrDefault(_ => _.PkId == model.ReviewBy)?.TrueName;
            });

            return models;
        }

        /// <summary>
        /// 获取返工工单
        /// </summary>
        /// <param name="reworkNo">返工单号</param>
        /// <returns>返工工单</returns>
        public VReworkOrder GetRework(string reworkNo)
        {
            var entity = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == reworkNo && _.Valid);
            if (entity == null)
            {
                return null;
            }
            var users = new UserMgr().QueryUsers(new List<int> { entity.CreateBy, entity.ReviewBy });
            var sites = mesDb.ReworkSites.AsNoTracking().Where(_ => _.ReworkNo == reworkNo && _.Valid).ToList();
            var items = mesDb.ReworkItems.AsNoTracking().Where(_ => _.ReworkNo == reworkNo && _.Valid).ToList();
            var reworkBoms = mesDb.ReworkBoms.AsNoTracking().Where(_ => _.ReworkNo == reworkNo && _.Valid).ToList();

            var model = Mapper.Map<VReworkOrder>(entity);
            model.Sites = Mapper.Map<List<VReworkSite>>(sites);
            model.Items = Mapper.Map<List<VReworkItem>>(items);
            model.Boms = Mapper.Map<List<VReworkBom>>(reworkBoms);

            model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
            model.CNReviewBy = users.FirstOrDefault(_ => _.PkId == model.ReviewBy)?.TrueName;

            return model;
        }

        /// <summary>
        /// 审核返工工单
        /// </summary>
        /// <param name="model">返工对象</param>
        public void ReviewRework(VReworkOrder model)
        {
            var entity = mesDb.ReworkOrders.AsNoTracking().FirstOrDefault(_ => _.ReworkNo == model.ReworkNo && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(140001);//返工单不存在
            }
            else if (entity.ReviewStatus != ReviewStatus.UnReviewed)
            {
                throw new MultiLanBizException(140013);//当前状态不允许审核
            }

            mesDb.ReworkOrders.Attach(entity);
            entity.ReviewStatus = model.ReviewStatus;
            entity.ReviewBy = model.ReviewBy;
            entity.ReviewTime = DateTime.Now;
            entity.ReviewDesc = model.ReviewDesc;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = model.ModifyTime;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    model = Mapper.Map<VReworkOrder>(entity);
                    var reworkItems = mesDb.ReworkItems.AsNoTracking().Where(_ => _.ReworkNo == model.ReworkNo && _.Valid).ToList();
                    var reworkItemNos = reworkItems.Select(_ => _.ReworkItemNo).Distinct().ToList();
                    var components = new List<Component>();
                    if (model.ReworkType == ReworkType.ByOrder)
                    {
                        components.AddRange(mesDb.Components.AsNoTracking().Where(_ => reworkItemNos.Contains(_.OrderNo) && _.Valid).ToList());
                    }
                    else if (model.ReworkType == ReworkType.ByWorkOrder)
                    {
                        components.AddRange(mesDb.Components.AsNoTracking().Where(_ => reworkItemNos.Contains(_.WorkOrderNo) && _.Valid).ToList());
                    }
                    else if (model.ReworkType == ReworkType.ByCabinet)
                    {
                        components.AddRange(mesDb.Components.AsNoTracking().Where(_ => reworkItemNos.Contains(_.CabinetNo) && _.Valid).ToList());
                    }
                    else if (model.ReworkType == ReworkType.ByPack)
                    {
                        components.AddRange(mesDb.Components.AsNoTracking().Where(_ => reworkItemNos.Contains(_.PackNo) && _.Valid).ToList());
                    }
                    var user = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.ReworkNo = entity.ReworkNo;
                        _.Reworking = true;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = model.ModifyTime;
                    });
                    mesDb.SaveChanges();

                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "返工审核",
                        LogStatus = model.ReviewStatus == ReviewStatus.Refused ? "正常" : "异常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = model.ReviewStatus == ReviewStatus.Refused ? "组件返工审核被拒绝" : $"组件返工审核通过，本次{model.CNReworkType}，共需返工{reworkItems.Count}" + (model.ReworkType == ReworkType.ByOrder ? "个订单" : (model.ReworkType == ReworkType.ByWorkOrder ? "个工单" : (model.ReworkType == ReworkType.ByCabinet ? "柜" : "包"))) + $"，合{components.Count}块",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"审核返工工单异常，返工单号：{model.ReworkNo}，异常信息：{ex.Message}");
                }
            });
        }
    }
}
